use std::fmt::Debug;
use std::sync::mpsc;
use std::sync::mpsc::{Receiver, Sender};
use std::thread;

use crate::gen_title;

pub fn ch4_13_1() {
    gen_title("ch4_13_1", 18);

    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
        tx.send(1).unwrap();
    });

    println!("receive {}", rx.recv().unwrap());
}

pub fn ch4_13_2() {
    gen_title("ch4_13_2", 18);

    let (tx, rx) = mpsc::channel();

    let handle = thread::spawn(move || {
        tx.send(1).unwrap();
    });

    handle.join().unwrap();

    println!("receive: {:?}", rx.try_recv());
}

pub fn ch4_13_3() {
    gen_title("ch4_13_3", 18);

    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
        let s = String::from("我, 飞走了哦");
        tx.send(s).unwrap();
        // println!("send: {:?}", s);
    });

    let received = rx.recv().unwrap();
    println!("receive: {:?}", received);
}

pub fn ch4_13_4() {
    gen_title("ch4_13_4", 18);

    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
        let vals = vec![
            String::from("hi"),
            String::from("from"),
            String::from("the"),
            String::from("thread"),
        ];

        for val in vals {
            tx.send(val).unwrap();
        }
    });

    for received in rx {
        println!("receive: {:?}", received);
    }
}

pub fn ch4_13_5() {
    gen_title("ch4_13_5", 18);

    let (tx, rx) = mpsc::channel();

    let tx1 = tx.clone();
    thread::spawn(move || {
        tx.send(String::from("hi from raw tx")).unwrap();
    });

    thread::spawn(move || {
        tx1.send(String::from("hi from cloned tx")).unwrap();
    });

    for received in rx {
        println!("receive: {:?}", received);
    }
}

pub fn ch4_13_6() {
    gen_title("ch4_13_6", 18);

    let (tx, rx) = mpsc::channel();

    let handle = thread::spawn(move || {
        println!("发送之前");
        tx.send(1).unwrap();
        println!("发送之后");
    });

    println!("睡眠之前");
    // thread::sleep(Duration::from_secs(3));
    println!("睡眠之后");

    println!("receive {}", rx.recv().unwrap());
    handle.join().unwrap();
}

pub fn ch4_13_7() {
    gen_title("ch4_13_7", 18);

    let (tx, rx) = mpsc::sync_channel(0);

    let handle = thread::spawn(move || {
        println!("发送之前");
        tx.send(1).unwrap();
        println!("发送之后");
    });

    println!("睡眠之前");
    // thread::sleep(Duration::from_secs(3));
    println!("睡眠之后");

    println!("receive {}", rx.recv().unwrap());
    handle.join().unwrap();
}

pub fn ch4_13_8() {
    gen_title("ch4_13_8", 18);

    let (tx, rx) = mpsc::sync_channel(1);

    let handle = thread::spawn(move || {
        println!("首次发送之前");
        tx.send(1).unwrap();
        println!("首次发送之后");
        tx.send(1).unwrap();
        println!("再次发送之后");
    });

    println!("睡眠之前");
    // thread::sleep(Duration::from_secs(3));
    println!("睡眠之后");

    println!("receive {}", rx.recv().unwrap());
    handle.join().unwrap();
}

pub fn ch4_13_9() {
    gen_title("ch4_13_9", 18);

    enum Fruit {
        Apple(u8),
        Orange(String),
    }

    let (tx, rx): (Sender<Fruit>, Receiver<Fruit>) = mpsc::channel();

    tx.send(Fruit::Orange("sweet".to_string())).unwrap();
    tx.send(Fruit::Apple(2)).unwrap();

    for _ in 0..2 {
        match rx.recv().unwrap() {
            Fruit::Apple(count) => println!("apple: {}", count),
            Fruit::Orange(flavor) => println!("orange: {}", flavor),
        }
    }
}

pub fn ch4_13_10() {
    gen_title("ch4_13_10", 18);

    trait Fruit: Debug {
        fn display(&self) {
            println!("{:?}", self);
        }
    }

    #[derive(Debug)]
    struct Orange(String);

    #[derive(Debug)]
    struct Apple(u8);

    impl Fruit for Orange {}

    impl Fruit for Apple {}

    let (tx, rx): (Sender<Box<dyn Fruit>>, Receiver<Box<dyn Fruit>>) = mpsc::channel();

    tx.send(Box::new(Orange("sweet".to_string()))).unwrap();
    tx.send(Box::new(Apple(2))).unwrap();

    for _ in 0..2 {
        rx.recv().unwrap().display();
    }
}

pub fn ch4_13_11() {
    gen_title("ch4_13_11", 18);

    let (send, recv) = mpsc::channel();
    let num_threads = 3;

    for i in 0..num_threads {
        let thread_send = send.clone();
        thread::spawn(move || {
            println!("thread {} send {}", i, i);
            thread_send.send(i).unwrap();
        });
    }

    drop(send);

    for x in recv {
        println!("receive {}", x);
    }

    println!("finished iterating");
}
